package internal

import (
	"context"
	"fmt"
	"github.com/beherochuling/beesoft_api/app/helper/framework"
	"go.opentelemetry.io/otel/trace"
	"strings"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gutil"

	"github.com/beherochuling/beesoft_api/app/helper/net"
	"github.com/beherochuling/beesoft_api/app/helper/net/websocket"
	"github.com/beherochuling/beesoft_api/app/helper/org/beesoft"
)

var (
	ctx             = context.Background()
	appEnv          = g.Config().MustGet(ctx, "app.env").String()
	tokenParameters = []string{"api_token"}
)

func parseStackFromError(ctx context.Context, err error) g.Map {
	var data g.Map

	e := gutil.Try(ctx, func(ctx context.Context) {
		if appEnv == "development" {
			s := gerror.Stack(err)
			stack := gstr.Replace(s, framework.Framework.RootDir()+"/", "")
			stack = gstr.Replace(stack, "\t", "    ")
			stacks := gstr.Split(stack, "\n")
			data = g.Map{
				"stack": stacks,
			}
		}

		if ctx != nil {
			ctx = context.WithValue(ctx, "middleware_error", err)
		}

		glog.Error(ctx, err)
	})

	if e != nil {
		fmt.Println("parseStackFromError: ", e)
	}

	return data
}
func middlewareErrorHandler(r *ghttp.Request) {
	r.Middleware.Next()

	if err := r.GetError(); err != nil {
		r.Response.ClearBuffer()
		if err.Error() == "http: request body too large" {
			net.NewResponse(r).ResponseRequestTooLarge()
		} else {
			net.NewResponse(r).ResponseServerError(err.Error(), parseStackFromError(r.Context(), err))
		}
	}
}
func middlewareSetUserId(r *ghttp.Request) {
	token := ""

	auth := gstr.ToLower(r.GetHeader("Authorization"))
	// authorization: Bearer v1,259645,318,b4a21f4f327782c2242b12f67f4fec3c
	if auth != "" && gstr.HasPrefix(auth, "bearer") {
		token = auth
	}

	if token == "" {
		for _, key := range tokenParameters {
			token = r.Get(key).String()
			if token != "" {
				break
			}
		}
	}

	if token != "" {
		u := beesoft.Beesoft.Passport.ParseToken(token)
		if u != nil && u.UserId != 0 {
			r.SetCtxVar("user_id", u.UserId)
		}
	}
	r.Middleware.Next()
}

// func middlewareOpenTracing(r *ghttp.Request) {
// 	// _, span := gtrace.NewSpan(r.Context(), "start")
// 	// span.SetAttributes(attribute.KeyValue{
// 	//	Key5:   "x.request.id",
// 	//	Value: attribute.StringValue("0a5d8354-5ee0-4861-8b1b-685dc3bbaac3"),
// 	// })
// 	//
// 	// glog.Info(r.Context(), "middleware open tracing")
// 	// // 集成kong的 X-Request-ID: 0a5d8354-5ee0-4861-8b1b-685dc3bbaac3
// 	glog.Info(r.Context(), "trace id: ", trace.SpanFromContext(r.Context()).SpanContext().TraceID().String())
// 	kongCorrelationID := r.GetHeader("X-Request-ID")
// 	g.DumpWithType("### kongCorrelationID", kongCorrelationID)
// 	if kongCorrelationID != "" {
// 		kongCorrelationID = strings.ReplaceAll(kongCorrelationID, "-", "")
// 		traceID, err := trace.TraceIDFromHex(kongCorrelationID)
// 		fmt.Println(traceID)
// 		if err == nil {
// 			ctx := trace.ContextWithRemoteSpanContext(r.Context(), trace.NewSpanContext(trace.SpanContextConfig{
// 				TraceID:    traceID,
// 				TraceFlags: trace.FlagsSampled,
// 			}))
// 			otel.Tracer("").Start(ctx, "inject")
// 			r.WithContext(ctx)
// 			// //ctx := gtrace.WithTraceID(r.Context(), traceID)
// 			// sc := trace.SpanContextFromContext(r.Context())
// 			// sc.WithTraceID(traceID)
// 			// g.DumpWithType(sc.HasTraceID(), sc.TraceID().String())
// 			// trace.ContextWithSpanContext(r.Context(), sc)
// 			// //g.DumpWithType(gtrace.GetTraceID(ctx))
// 			// ////spanContextConfig := trace.SpanContextConfig{
// 			// ////	TraceID: traceID,
// 			// ////}
// 			// ////var spanContext = trace.NewSpanContext(spanContextConfig)
// 			// //trace.ContextWithSpanContext(r.Context(), trace.SpanContext{}.WithTraceID(traceID))
// 		}
// 	}
// 	glog.Info(r.Context(), "trace id: ", trace.SpanFromContext(r.Context()).SpanContext().TraceID().String())
// 	// g.DumpWithType("### span trace id", span.SpanContext().TraceID(), span.SpanContext().SpanID())
// 	// defer span.End()
// 	r.Middleware.Next()
// }

func initRoute() {
	server := g.Server()

	server.BindHookHandlerByMap("/*", map[ghttp.HookName]ghttp.HandlerFunc{
		ghttp.HookBeforeServe: func(r *ghttp.Request) {
			if !r.IsFileRequest() {
				kongCorrelationID := r.GetHeader("X-Request-ID")
				if kongCorrelationID != "" {
					kongCorrelationID = strings.ReplaceAll(kongCorrelationID, "-", "")
					traceID, _ := trace.TraceIDFromHex(kongCorrelationID)
					ctx := trace.ContextWithRemoteSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
						TraceID: traceID,
					}))
					r.SetCtx(ctx)
				}
			}
		},
	})

	server.BindMiddlewareDefault(middlewareSetUserId)
	if !g.Config().MustGet(ctx, "app.route.disableDefaultMiddlewareErrorHandler", false).Bool() {
		server.BindMiddlewareDefault(middlewareErrorHandler)
	}
	if !g.Config().MustGet(ctx, "app.route.disableDefault404Route", false).Bool() {
		server.BindHandler("/*any", func(r *ghttp.Request) {
			net.NewResponse(r).ResponseNotFound("not found")
		})
	}
	if !g.Config().MustGet(ctx, "app.route.disableDefaultPingRoute", false).Bool() {
		server.Group("/", func(group *ghttp.RouterGroup) {
			group.ALL("/ping", func(r *ghttp.Request) {
				net.NewResponse(r).WriteHtml("pong")
			})
		})
	}

	websocket.Init(server)
	// beesoftStorage.Init(backend)
	// beesoftPayment.Init(backend)
}
